home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / emac16ds.zip / SEARCH.ASM < prev    next >
Assembly Source File  |  1991-06-13  |  28KB  |  1,219 lines

  1. ;History:107,1
  2. ;Mon Apr 23 23:22:13 1990 Add \( and \) capability (won't work with *)
  3. ;Sun Apr 22 23:30:23 1990 omatch_NCCL bombed on the first failure to match.
  4. ;Sun Apr 22 23:12:21 1990 don't bomb locate on null classes.
  5. ;Wed Apr 11 22:55:42 1990 three alternations (\|) would cause a crash.
  6. ;Wed Apr 11 22:54:54 1990 \W should include newline.
  7. ;Wed Nov 29 23:58:27 1989 Add support for \|
  8. ;Tue Nov 07 23:45:44 1989 match newlines in character classes.
  9. ;Mon Nov 06 00:40:16 1989 try to make backwards regexp searches work.
  10. ;Sat Nov 05 22:05:14 1988 let CR LF match LINENEW.
  11. ;10-08-88 08:48:54 add \n to regexp search.
  12. ;09-26-88 21:23:42 add case translation for character classes.
  13. ;08-19-88 23:36:40 closure didn't work because omatch iterated on matching.
  14. ;08-13-88 22:12:46 try forwards again.
  15. ;07-24-88 16:42:24 BOL and EOL match BOB and EOB respectively.
  16. ;07-21-88 22:49:18 add optimized search backwards.
  17. ;07-20-88 00:15:38 too late at night to continue...
  18. ;07-20-88 00:02:35 optimize forward searches.
  19. ;07-19-88 23:38:07 use the right omatch_chr for both regexps and literals.
  20. ;07-19-88 00:51:06 initialize the case table.
  21. ;07-18-88 21:20:18 don't increment di twice in omatch_NCCL
  22. ;07-18-88 00:04:34 replace bad patterns with "".
  23. ;07-17-88 23:15:23 Check for topbot right after incrementing di.
  24. ;07-17-88 22:55:12 search *at* the end_ptr (check for end_ptr after searching).
  25. ;07-17-88 18:54:53 when searching backwards, don't search past right_ptr.
  26. ;07-17-88 10:59:27 save di around omatch()
  27. ;07-17-88 10:42:13 omatch_CHR was incrementing di even if it didn't match.
  28. ;06-06-88 23:58:09 change the regexp chars to match Gnu's.
  29. ;07-06-87 06:55:31 Use botbot for eof, not LINENEW
  30.     include    memory.def
  31.  
  32. data    segment    byte public
  33.  
  34. b_struc    struc
  35. b    db    ?
  36. b_struc    ends
  37.  
  38. w_struc    struc
  39. w    dw    ?
  40. w_struc    ends
  41.  
  42.     extrn    outpat: byte
  43.     extrn    OUTPATSIZE: abs
  44. inpat_ptr    dw    ?        ;beginning of input pattern.
  45. direction    dw    ?        ;routine to increment di in correct direction.
  46. scan_char    dw    ?        ;routine to scan for a character.
  47. end_ptr        dw    ?        ;end of region we're searching.
  48. right_ptr    dw    ?        ;rightmost end of region we're searching.
  49. clo_si        dw    ?        ;saved pointer for closure.
  50. last_ptr    dw    ?        ;pointer to last character matched.
  51. which_chr    dw    ?        ;which omatch_CHR to use.
  52. this_pattern    dw    ?        ;->this pattern (for closure).
  53. last_pattern    dw    ?        ;->previous pattern (for closure).
  54. last_or        dw    ?        ;->last or pointer.
  55. paren_count    dw    ?        ;number of unmatched parentheses.
  56.  
  57.     extrn    textseg: word
  58.  
  59. init_case        dw    init_case_table
  60. case_ignore_table    db    256 dup(?)
  61.  
  62. data    ends
  63.  
  64.  
  65. bufseg    segment    public
  66.  
  67.     extrn    toptop: word
  68.     extrn    topbot: word
  69.     extrn    bottop: word
  70.     extrn    botbot: word
  71.  
  72. bufseg    ends
  73.  
  74.  
  75. code    segment    byte public
  76.     assume    cs:code, ds:data
  77.  
  78.     public    slowly
  79.  
  80.     extrn    get_mark: near, set_mark_si: near
  81.     extrn    get_syntax: near
  82.  
  83.     public    search
  84. search:
  85. ;enter with ch=start mark, cl=end mark, dh=first mark, dl=last mark.
  86. ;start searching at mark ch.  If the string is found, then return the
  87. ;  beginning in mark dh, and the end in mark dl, and cy=0.  If the string
  88. ;  wasn't found, return cy=1.
  89.     push    dx            ;save the first, last marks.
  90.     push    es
  91.     mov    es,textseg
  92.     assume    es:bufseg
  93.     push    ds            ;save ds
  94.     push    es
  95.     pop    ds
  96.     assume    ds:bufseg        ;for get_mark
  97.     mov    al,cl            ;get the end mark.
  98.     push    cx
  99.     call    get_mark
  100.     mov    bp,si            ;save a copy of it.
  101.     pop    cx
  102.     mov    al,ch            ;get the start mark.
  103.     call    get_mark
  104.     pop    ds            ;restore ds
  105.     assume    ds:data
  106.     mov    end_ptr,bp        ;save a copy of the end.
  107.     mov    right_ptr,bp        ;save a copy of the end.
  108.     mov    direction,offset inc_di
  109.     cmp    si,end_ptr        ;start>=end?
  110.     jb    search_4        ;no.  (doesn't matter if they're equal)
  111.     mov    direction,offset dec_di    ;yes, go in reverse direction.
  112.     mov    right_ptr,si        ;yes, remember that start is rightmost.
  113. search_4:
  114.     mov    di,si            ;get the pointer to our string.
  115.     call    slowly
  116.     pop    es
  117.     assume    es:data
  118.     pop    dx
  119.     jc    search_1        ;not found.
  120.  
  121.     push    ds
  122.     mov    ds,textseg        ;for set_mark_si
  123.     assume    ds:bufseg
  124.     mov    al,dh
  125.     mov    si,di
  126.     call    set_mark_si        ;set the first mark.
  127.  
  128.     mov    si,last_ptr
  129.     mov    al,dl
  130.     call    set_mark_si        ;set the last mark.
  131.  
  132.     pop    ds
  133.     assume    ds:data
  134.     clc                ;return a match.
  135.     ret
  136. search_1:
  137.     stc                ;return no match.
  138.     ret
  139.  
  140.  
  141.     assume    ds:data, es:bufseg
  142.  
  143.  
  144. scan_char_literal:
  145.     or    sp,sp            ;ensure NZ in case cx=0.
  146.     repne    scasb            ;search for the character.
  147.     ret
  148.  
  149.  
  150. scan_char_fold:
  151.     xlat
  152.     mov    ah,al
  153.     or    sp,sp            ;if cx=0, be sure to return nz.
  154.     jcxz    scan_char_fold_2
  155.     shr    cx,1            ;we unrolled the loop once.
  156.     jnc    scan_char_fold_1    ;if even, start at the top.
  157.     inc    cx            ;otherwise, add one for the odd
  158.     jmp    short scan_char_fold_3    ;  iteration, and jump to it.
  159. scan_char_fold_1:
  160.     mov    al,es:[di]        ;unroll this puppy once.
  161.     add    di,dx
  162.     xlat
  163.     cmp    al,ah            ;compare them.
  164.     je    scan_char_fold_2    ;if equal, we're done.
  165. scan_char_fold_3:
  166.     mov    al,es:[di]        ;now do the second set.
  167.     add    di,dx
  168.     xlat
  169.     cmp    al,ah
  170.     loopne    scan_char_fold_1
  171. scan_char_fold_2:
  172.     mov    al,ah            ;get our character back.
  173.     ret
  174.  
  175.  
  176. slowly:
  177. ;es:si -> first char to look at.
  178. ;es:right_ptr -> after last char to look at.
  179. ;return cy if no match,
  180. ;  else nc, si->start of match, last_ptr->after end of match.
  181.     cmp    di,topbot        ;at topbot already?
  182.     jne    slowly_0
  183.     mov    di,bottop
  184. slowly_0:
  185.     mov    ax,which_chr        ;does the pattern start with a CHR?
  186.     cmp    ax,word ptr outpat
  187.     jne    slowly_1        ;no.
  188.     cmp    outpat+2,CR        ;searching for literal CR?
  189.     je    slowly_1        ;yes - don't optimize because of CRLFs.
  190.     cmp    outpat+2,LF        ;searching for literal LF?
  191.     je    slowly_1        ;yes - don't optimize because of CRLFs.
  192.  
  193.     mov    scan_char,offset scan_char_literal
  194.     cmp    ax,offset omatch_CHR    ;Are we folding case?
  195.     je    quickly_1        ;no.
  196.     mov    scan_char,offset scan_char_fold
  197. quickly_1:
  198.     cmp    direction,offset inc_di    ;Are we going forwards?
  199.     je    forwards_0        ;yes.
  200.   if 0 ;disable optimization for now.
  201.     jmp    slowly_1
  202.   endif
  203.     jmp    backwards_0        ;no.
  204.  
  205. slowly_1:
  206.     mov    si,offset outpat    ;start at beginning of pattern.
  207.     mov    bx,offset case_ignore_table
  208.     push    di            ;remember where we're starting.
  209.     call    omatch            ;now search.
  210.     pop    di
  211.     jnc    slowly_succeed        ;we found a match
  212. ;not found, should we give up?
  213.     cmp    di,end_ptr        ;at the end yet?
  214.     je    slowly_fail        ;yes - not found.
  215. ;not found, we have to bump di.
  216.     call    direction
  217.     jmp    slowly_1
  218. slowly_fail:
  219.     stc                ;not found.
  220.     ret
  221. slowly_succeed:
  222.   if 1    ;an attempt to make backwards regexp searches work right.
  223.     cmp    direction,offset inc_di    ;Are we going forwards?
  224.     je    slowly_done        ;yes - we're done now.
  225. slowly_backwards_again:
  226.     call    dec_di            ;move backwards.
  227.     push    last_ptr        ;remember the pointer to the end of it.
  228.     mov    si,offset outpat    ;start at beginning of pattern.
  229.     mov    bx,offset case_ignore_table
  230.     push    di
  231.     call    omatch            ;did it match?
  232.     pop    di
  233.     pop    ax
  234.     jc    slowly_backwards_done    ;no - we're done.
  235.     cmp    ax,last_ptr        ;did last_ptr change?
  236.     je    slowly_backwards_again    ;no, we can try again.
  237. slowly_backwards_done:
  238.     mov    last_ptr,ax
  239.     call    inc_di            ;point to the last match again.
  240. slowly_done:
  241.   endif
  242.     clc
  243.     ret
  244.  
  245.     public    forwards_0
  246. forwards_0:
  247.     mov    bx,offset case_ignore_table
  248.     mov    al,outpat+2        ;get the character
  249.     cmp    di,bottop        ;are we in the bottom?
  250.     jae    forwards_2        ;yes - don't search the top.
  251.  
  252.     mov    cx,topbot        ;should we search to topbot
  253.     cmp    cx,end_ptr        ;  or to end_ptr?
  254.     jbe    forwards_3
  255.     mov    cx,end_ptr        ;just to end_ptr.
  256. forwards_3:
  257.     sub    cx,di            ;compute the amount left in the top.
  258.     mov    dx,1
  259.     call    scan_char        ;scan for our character.
  260.     je    forwards_1        ;we found it!
  261.  
  262.     cmp    di,end_ptr        ;are we at the end?
  263.     jae    slowly_fail        ;yes - no match.
  264.  
  265.     mov    di,bottop
  266. forwards_2:
  267.     mov    cx,end_ptr        ;we only need search that far.
  268.     sub    cx,di
  269.     mov    dx,1
  270.     call    scan_char        ;scan for our character.
  271.     jne    slowly_fail        ;we didn't find it.
  272. forwards_1:
  273.     mov    si,offset outpat+3    ;start at beginning of pattern.
  274.     push    di            ;remember where we're starting.
  275.     call    omatch            ;now search.
  276.     pop    di
  277.     jnc    forwards_4        ;we matched - return it.
  278.     cmp    di,end_ptr        ;are we at the end?
  279.     jb    forwards_0        ;no - keep matching.
  280. slowly_fail_j_1:
  281.     jmp    slowly_fail        ;yes - no match.
  282. forwards_4:
  283.     dec    di            ;remember that we actually started
  284.     jmp    slowly_succeed        ;  one character into the pattern.
  285.  
  286.  
  287.     public    backwards_0
  288. backwards_0:
  289.     mov    bx,offset case_ignore_table
  290.     mov    al,outpat+2        ;get the character
  291.     cmp    di,bottop        ;are we in the top?
  292.     jb    backwards_2        ;yes - don't search the bottom.
  293.     je    backwards_5
  294.  
  295.     mov    si,bottop        ;should we search to bottop
  296.     cmp    si,end_ptr        ;  or to end_ptr?
  297.     jae    backwards_3
  298.     mov    si,end_ptr        ;just to end_ptr.
  299. backwards_3:
  300.  
  301.     dec    di
  302.     mov    cx,di            ;compute the amount left in the bottom.
  303.     sub    cx,si
  304.     inc    cx            ;be sure to look at where di points.
  305.     std
  306.     mov    dx,-1
  307.     call    scan_char        ;scan for our character.
  308.     cld
  309.     je    backwards_1        ;we found it!
  310.  
  311. backwards_5:
  312.     cmp    di,end_ptr        ;are we at the end?
  313.     jbe    slowly_fail_j_1        ;yes - no match.
  314.  
  315.     mov    di,topbot
  316.     dec    di
  317. backwards_2:
  318.     mov    cx,di            ;we only search here if end_ptr is here.
  319.     sub    cx,end_ptr
  320.     inc    cx            ;be sure to compare where di is.
  321.     std
  322.     mov    dx,-1
  323.     call    scan_char        ;scan for our character.
  324.     cld
  325.     jne    slowly_fail_j_1        ;we didn't find it.
  326. backwards_1:
  327.     mov    si,offset outpat+3    ;start at beginning of pattern.
  328.     push    di            ;remember where we're starting.
  329.     add    di,2            ;we post-decremented.
  330.     call    omatch            ;now search.
  331.     pop    di
  332.     jnc    backwards_4        ;we suceeded.
  333.     inc    di
  334.     cmp    di,end_ptr        ;are we after the end?
  335.     jb    slowly_fail_j_1        ;yes - no match.
  336.     dec    di
  337.     jmp    backwards_0
  338. backwards_4:
  339.     inc    di            ;remember that we post-decremented,
  340.     jmp    slowly_succeed        ;  so we're one character too far.
  341.  
  342. inc_di:
  343. ;bump di forwards.
  344.     inc    di
  345.     cmp    di,topbot        ;at bottom of top?
  346.     je    inc_di_1        ;yes - can't possibly be split over newline.
  347.     cmp    es:[di-1].w,LINENEW    ;did we just move into a newline?
  348.     jne    inc_di_2        ;no.
  349.     inc    di            ;yes - skip LF part of newline.
  350.     cmp    di,topbot        ;at topbot already?
  351.     jne    inc_di_2
  352. inc_di_1:
  353.     mov    di,bottop
  354. inc_di_2:
  355.     ret
  356.  
  357. dec_di:
  358. ;bump di backwards.
  359.     cmp    di,bottop        ;at top of bottom?
  360.     jne    dec_di_1        ;no.
  361.     mov    di,topbot        ;yes - load bottom of top.
  362. dec_di_1:
  363.     dec    di            ;back up to previous character.
  364.     cmp    es:[di-1].w,LINENEW    ;at newline?
  365.     jne    dec_di_2        ;no.
  366.     cmp    di,bottop        ;at top of bottom now?
  367.     je    dec_di_2        ;yes - can't possibly be split over newline.
  368.     dec    di            ;yes - skip to beginning of newline.
  369. dec_di_2:
  370.     ret
  371.  
  372.  
  373. omatch:
  374. ;return nc if we matched, cy if not.
  375. ;es:di -> source text
  376. ;ds:si -> pattern
  377. omatch_0:
  378.     cmp    di,topbot        ;at bottom of top?
  379.     jne    omatch_1
  380.     mov    di,bottop        ;yes, go to top of bottom.
  381. omatch_1:
  382.     lodsw
  383.     call    ax
  384.     jnc    omatch_0
  385.     ret
  386.  
  387.  
  388. ;each of the omatch_XXX routines operates under the following constraints
  389. ;  on failure, return with cy set.
  390. ;  on matching (only used by omatch_EOS right now), return to caller's caller
  391. ;    with cy clear.
  392. ;  on success, bump si as needed so that it points to the next omatch,
  393. ;    bump di as needed (either zero or one), and return with cy clear.
  394.  
  395.     public    omatch_EOS
  396. omatch_EOS:
  397.     mov    last_ptr,di        ;remember the last thing we matched.
  398.     add    sp,2            ;pop our return address.
  399.     clc                ;if we get to the end of the
  400.     ret                ;  pattern, then we matched.
  401.  
  402.     public    omatch_CLO
  403. omatch_CLO:
  404.     push    di            ;save the first closure pattern.
  405.     mov    CLO_si,si        ;remember the pattern we're closing.
  406. ;Note that we don't have to worry about CLO_si being global because the
  407. ;  next pattern can't be another closure.
  408. ;match as many as fit the next pattern
  409.     mov    bx,offset case_ignore_table
  410. omatch_CLO_1:
  411.     mov    si,CLO_si        ;get the pattern being closed.
  412.     cmp    di,topbot        ;at bottom of top?
  413.     jne    omatch_CLO_5
  414.     mov    di,bottop        ;yes, go to top of bottom.
  415. omatch_CLO_5:
  416.     lodsw
  417.     call    ax
  418.     jnc    omatch_CLO_1
  419.     pop    bx
  420. ;match only as many as fit the pattern after the next pattern.
  421. omatch_CLO_2:
  422.     push    si
  423.     push    di
  424.     push    bx
  425.     mov    bx,offset case_ignore_table
  426.     call    omatch            ;try to match rest of pattern.
  427.     pop    bx
  428.     pop    di
  429.     pop    si
  430.     jnc    omatch_CLO_4        ;go if it matched.
  431.     cmp    di,bottop        ;backing up past the point?
  432.     jne    omatch_CLO_3        ;no - just decrement.
  433.     mov    di,topbot        ;yes - get the bottom of the top.
  434. omatch_CLO_3:
  435.     dec    di            ;point to the previous character.
  436.     cmp    di,bx            ;zero or more matches still?
  437.     jae    omatch_CLO_2        ;yes.
  438.     stc                ;no matches--return no match.
  439.     ret
  440. omatch_CLO_4:
  441.     pop    bx            ;get rid of our return address.
  442.     ret
  443.  
  444.  
  445. omatch_PAREN:
  446.     push    si
  447.     push    di
  448.     mov    bx,offset case_ignore_table
  449.     call    omatch            ;try to match rest of pattern.
  450.     jnc    omatch_PAREN_1        ;go if it matched.
  451.     pop    di
  452.     pop    si
  453.     ret
  454. omatch_PAREN_1:
  455.     add    sp,4            ;get rid of si and di.
  456. ;guaranteed nc.
  457.     ret
  458.  
  459. omatch_OR:
  460.     add    si,2            ;skip past our param.
  461.     push    si
  462.     push    di
  463.     mov    bx,offset case_ignore_table
  464.     call    omatch            ;try to match rest of pattern.
  465.     jnc    omatch_OR_1        ;go if it matched.
  466.     pop    di
  467.     pop    si
  468.     push    si
  469.     mov    si,[si-2]        ;point to the next or-clause.
  470.     push    di
  471.     call    omatch
  472.     jnc    omatch_OR_1        ;go if it matched.
  473.     pop    di
  474.     pop    si
  475. ;guaranteed cy.
  476.     ret
  477. omatch_OR_1:
  478.     add    sp,6            ;get rid of si,di, and our return addr.
  479. ;guaranteed nc.
  480.     ret
  481.  
  482.  
  483.     public    omatch_CHR
  484. omatch_CHR:
  485.     cmp    di,right_ptr        ;are we at the end?
  486.     je    omatch_CHR_skip        ;yes - we never match CHR
  487.     cmp    es:[di].w,LINENEW
  488.     je    omatch_CHR_linenew
  489.     cmpsb
  490.     je    omatch_yes        ;if they're the same, match again.
  491.     dec    di            ;don't modify buffer pointer if no match.
  492.     stc
  493.     ret
  494. omatch_CHR_linenew:
  495.     cmp    [si].b,CR        ;got a LINENEW, are we looking for one?
  496.     jne    omatch_CHR_skip        ;no.
  497.     mov    ax,which_chr        ;is the next one another char?
  498.     cmp    [si+1].w,ax
  499.     jne    omatch_CHR_skip        ;no - no match.
  500.     cmp    [si+1+2].b,LF        ;Are we really looking for a linenew?
  501.     jne    omatch_CHR_skip        ;no - no match.
  502.     add    si,1+2+1        ;skip past the two of them.
  503.     add    di,2            ;skip in the buffer also.
  504.     clc
  505.     ret
  506. omatch_CHR_skip:
  507.     inc    si            ;skip the pattern character.
  508. omatch_CHR_no:
  509.     stc
  510.     ret
  511. omatch_yes:
  512.     clc
  513.     ret
  514.  
  515.  
  516.     public    omatch_NCHR
  517. omatch_NCHR:
  518.     cmp    di,right_ptr        ;are we at the end?
  519.     je    omatch_CHR_skip        ;yes - we never match CHR
  520.     cmp    es:[di].w,LINENEW
  521.     je    omatch_CHR_linenew
  522.     lodsb
  523.     xlat
  524.     mov    ah,al
  525.     mov    al,es:[di]
  526.     inc    di
  527.     xlat
  528.     cmp    ah,al
  529.     je    omatch_yes        ;if they're the same, match again.
  530.     dec    di            ;don't modify buffer pointer if no match.
  531.     stc
  532.     ret
  533.  
  534.  
  535. omatch_NL:
  536.     cmp    di,right_ptr        ;are we at the end?
  537.     je    omatch_NL_no        ;yes - we never match newline.
  538.     cmp    es:[di].w,LINENEW    ;is it newline?
  539.     jne    omatch_NL_no        ;no - don't match it.
  540.     add    di,2            ;yes - skip it.
  541.     clc
  542.     ret
  543. omatch_NL_no:
  544.     stc
  545.     ret
  546.  
  547.  
  548.     public    omatch_BOB
  549. omatch_BOB:
  550. ;match beginning of buffer.
  551.     cmp    di,toptop        ;are we at the beginning of the buffer?
  552.     je    omatch_yes        ;yes.
  553.     stc
  554.     ret
  555.  
  556.  
  557.     public    omatch_BOL
  558. omatch_BOL:
  559. ;match beginning of line.
  560.     push    di            ;we might have to look at the top.
  561.     cmp    di,bottop        ;are we at the point?
  562.     jne    omatch_BOL_1        ;yes - ok.
  563.     mov    di,topbot        ;no - get the top.
  564. omatch_BOL_1:
  565.     cmp    di,toptop
  566.     je    omatch_BOL_2
  567.     cmp    es:[di-2].w,LINENEW
  568.     pop    di
  569.     jne    omatch_CHR_no
  570.     clc
  571.     ret
  572. omatch_BOL_2:
  573.     pop    di
  574.     clc
  575.     ret
  576.  
  577.  
  578.     public    omatch_ISW
  579. omatch_ISW:
  580. ;match word character.
  581.     cmp    di,botbot
  582.     je    omatch_CHR_no
  583.     cmp    es:[di].w,LINENEW
  584.     je    omatch_CHR_no
  585.     call    chars_around_di
  586.     test    al,1            ;word character?
  587.     je    omatch_CHR_no        ;nope--no match.
  588.     inc    di            ;match the character.
  589.     clc
  590.     ret
  591.  
  592.  
  593.     public    omatch_NOW
  594. omatch_NOW:
  595. ;match NOt Word character.
  596.     cmp    di,botbot
  597.     je    omatch_no
  598.     cmp    es:[di].w,LINENEW
  599.     je    omatch_NOW_1
  600.     call    chars_around_di
  601.     test    al,1            ;whitespace before and word after?
  602.     jne    omatch_no        ;nope--no match.
  603.     inc    di            ;match the character.
  604.     clc
  605.     ret
  606. omatch_NOW_1:
  607.     add    di,2            ;skip past the newline,
  608.     clc                ;  and match.
  609.     ret
  610.  
  611.  
  612.     public    omatch_BOW
  613. omatch_BOW:
  614. ;match beginning of word.
  615.     cmp    di,botbot
  616.     je    omatch_no
  617.     cmp    es:[di].w,LINENEW
  618.     je    omatch_no
  619.     call    chars_around_di
  620.     cmp    al,1            ;whitespace before and word after?
  621.     jne    omatch_no        ;nope--no match.
  622.     clc
  623.     ret
  624.  
  625.  
  626.     public    omatch_EOW
  627. omatch_EOW:
  628. ;match end of word.
  629.     call    chars_around_di
  630.     cmp    al,2            ;word before and whitespace after?
  631.     jne    omatch_no        ;nope--no match.
  632.     clc
  633.     ret
  634.  
  635.  
  636.     public    omatch_WOR
  637. omatch_WOR:
  638. ;match end of word.
  639.     call    chars_around_di
  640.     cmp    al,2            ;word before and whitespace after?
  641.     je    omatch_WOR_yes        ;yes - match.
  642.     cmp    al,1            ;whitespace before and word after?
  643.     je    omatch_WOR_yes        ;yes - match.
  644.     stc
  645.     ret
  646. omatch_WOR_yes:
  647.     clc
  648.     ret
  649.  
  650.  
  651.     public    omatch_NWR
  652. omatch_NWR:
  653. ;match end of word.
  654.     call    chars_around_di
  655.     cmp    al,0            ;whitespace before and whitespace after?
  656.     je    omatch_NWR_yes        ;yes - match.
  657.     cmp    al,3            ;word before and word after?
  658.     je    omatch_NWR_yes        ;yes - match.
  659.     stc
  660.     ret
  661. omatch_NWR_yes:
  662.     clc
  663.     ret
  664.  
  665.  
  666.     public    omatch_EOB
  667. omatch_EOB:
  668. ;match end of buffer.
  669.     cmp    di,botbot        ;are we at the end of the buffer?
  670.     je    omatch_NWR_yes        ;yes.
  671.     stc
  672.     ret
  673.  
  674.  
  675.     public    omatch_EOL
  676. omatch_EOL:
  677. ;match end of line.
  678.     cmp    di,botbot        ;are we at the end?
  679.     je    omatch_EOL_yes        ;yes.
  680.     cmp    es:[di].w,LINENEW
  681.     jne    omatch_no
  682. omatch_EOL_yes:
  683.     clc
  684.     ret
  685. omatch_no:
  686.     stc
  687.     ret
  688.  
  689.  
  690.     public    omatch_ANY
  691. omatch_ANY:
  692. ;match any single character.
  693.     cmp    di,right_ptr        ;are we at the end?
  694.     je    omatch_no        ;yes - we never match ANY
  695.     cmp    es:[di].w,LINENEW    ;we never match EOL.
  696.     je    omatch_no
  697.     inc    di
  698.     clc
  699.     ret
  700.  
  701.  
  702.     public    omatch_CCL
  703. omatch_CCL:
  704. ;match a character class.
  705.     cmp    di,right_ptr        ;are we at the end?
  706.     je    omatch_ccl_no        ;yes - we never match CCL
  707.     cmp    es:[di].w,LINENEW    ;we never match EOL.
  708.     je    omatch_ccl_newline
  709.     call    locate            ;see if it's in our set.
  710.     jnz    omatch_no        ;nope.
  711.     inc    di
  712.     clc
  713.     ret
  714. omatch_ccl_newline:
  715.     lea    ax,[di+1]        ;are we near the end?
  716.     cmp    ax,right_ptr
  717.     je    omatch_ccl_no        ;yes - no match.
  718.     cmp    ds:[si+1].w,LINENEW    ;does the class begin with crlf?
  719.     jne    omatch_ccl_no        ;no - don't match it.
  720.     lodsb                ;skip past this pattern.
  721.     xor    ah,ah
  722.     add    si,ax
  723.     add    di,2
  724.     clc
  725.     ret
  726.  
  727.  
  728.     public    omatch_NCCL
  729. omatch_NCCL:
  730. ;match not in a character class.
  731.     cmp    di,right_ptr        ;are we at the end?
  732.     je    omatch_ccl_no        ;yes - we never match NCCL
  733.     cmp    es:[di].w,LINENEW    ;we only match EOL if it begins the class.
  734.     je    omatch_ccl_no
  735.     call    locate            ;see if it's in our set.
  736.     jz    omatch_no        ;yes - we don't match.
  737.     inc    di
  738.     clc
  739.     ret
  740. omatch_ccl_no:
  741.     lodsb                ;skip past the pattern.
  742.     xor    ah,ah
  743.     add    si,ax
  744.     stc
  745.     ret
  746.  
  747.  
  748. locate:
  749. ;es:di -> search string, bx -> case translate table.
  750. ;ds:si -> CCL
  751. ;exit with zr if found, nz if not found, si -> after the pattern.
  752.     push    cx
  753.     lodsb                ;get the count.
  754.     mov    cl,al
  755.     xor    ch,ch
  756.     jcxz    locate_1        ;if empty class, it doesn't match.
  757.     mov    al,es:[di]        ;get the character we're trying to match.
  758.     xlat                ;case translate it.
  759.     mov    ah,al            ;keep it somewhere safe.
  760. locate_2:
  761.     lodsb
  762.     xlat
  763.     cmp    al,ah            ;is this one it?
  764.     loopne    locate_2
  765.     lahf                ;remember whether or not we found it.
  766.     add    si,cx
  767.     sahf
  768.     pop    cx
  769.     ret
  770. locate_1:
  771.     or    sp,sp            ;return nz.
  772.     pop    cx
  773.     ret
  774.  
  775.  
  776. chars_around_di:
  777. ;return al bit 1=syntax of char to left of point.
  778. ;    al bit 0=syntax of char to right of point.
  779.     push    di            ;get the character before point.
  780.     cmp    di,bottop        ;are we at the point?
  781.     jne    chars_around_di_1    ;yes.
  782.     mov    di,topbot
  783. chars_around_di_1:
  784.     xor    al,al            ;if no character, it's whitespace.
  785.     cmp    di,toptop
  786.     je    chars_around_di_2
  787.     mov    al,es:[di-1]
  788.     call    get_syntax        ;get the syntax for the char before point.
  789.     and    al,1            ;isolate the 'word' bit.
  790. chars_around_di_2:
  791.     shl    al,1
  792.     mov    ah,al
  793.     pop    di
  794.  
  795.     xor    al,al            ;if no character, it's whitespace.
  796.     cmp    di,botbot        ;are we at the end?
  797.     je    chars_around_di_3    ;yes - can't match beginning of word.
  798.     mov    al,es:[di]
  799.     call    get_syntax
  800.     and    al,1
  801. chars_around_di_3:
  802.     or    al,ah            ;include the syntax of the char to left of point.
  803.     ret
  804.  
  805.  
  806.     assume    ds:data
  807.  
  808.     public    set_pattern
  809. set_pattern:
  810. ;enter with si, cx->pattern.  dx<>0 if regular expression.  di <> 0 if we
  811. ;  want to fold case.
  812. ;exit with cy=1 if error.
  813.     call    init_case
  814.     mov    ax,offset omatch_CHR
  815.     or    di,di
  816.     je    set_pattern_0
  817.     mov    ax,offset omatch_NCHR
  818. set_pattern_0:
  819.     mov    which_chr,ax        ;remember which omatch_CHR to use.
  820.     or    dx,dx
  821.     jne    regexp_pat
  822.     mov    di,offset outpat
  823.     jcxz    set_pattern_1
  824.     mov    bp,offset outpat-2
  825.     add    bp,OUTPATSIZE
  826. set_pattern_2:
  827.     cmp    di,bp            ;do we have enough room?
  828.     jae    set_pattern_3        ;no - quit now.
  829.     stosw                ;store the appropriate comparison omatcher.
  830.     movsb
  831.     loop    set_pattern_2
  832. set_pattern_1:
  833.     mov    ax,offset omatch_EOS    ;store the end of string.
  834.     stosw
  835.     clc
  836.     ret
  837. set_pattern_3:
  838.     stc
  839.     ret
  840.  
  841.  
  842.     public    regexp_pat
  843. regexp_pat:
  844. ;enter with si, cx->pattern.
  845. ;exit with cy=1 if error.
  846.     mov    bx,cx
  847.     mov    [si+bx],byte ptr 0    ;store the terminating null.
  848.     call    makepat
  849.     jnc    regexp_pat_1
  850.     mov    word ptr outpat,offset omatch_EOS    ;uh-oh, bad pattern -- null it.
  851. regexp_pat_1:
  852.     ret
  853.  
  854.  
  855. makepat:
  856. ;si -> source pat (null terminated)
  857. ;di -> dest pattern, dx -> last dest entry.
  858. ;bx -> last closure
  859. ;return cy=1 if error.
  860.     mov    inpat_ptr,si
  861.     mov    di,offset outpat
  862.     mov    dx,OUTPATSIZE
  863.     add    dx,di
  864.     mov    last_pattern,-1        ;remember where the previous pattern started.
  865.     mov    last_or,di        ;remember that it's here.
  866.     mov    paren_count,0        ;start with no parens.
  867. makepat_1:
  868.     lodsb                ;get the first character.
  869.     or    al,al            ;end of string?
  870.     je    makepat_0        ;yes.
  871.  
  872.     mov    this_pattern,di        ;remember where this pattern starts.
  873.  
  874.     cmp    al,'\'            ;are we escaping something?
  875.     jne    makepat_a
  876.     cmp    byte ptr [si],0        ;is the '\' at the end?
  877.     je    makepat_9        ;yes - just use \.
  878.     lodsb                ;get the escaped char.
  879.     call    escaped_char        ;check for the special escapes.
  880.     jmp    makepat_2
  881. makepat_a:
  882.     cmp    al,'.'
  883.     jne    makepat_3
  884.     mov    ax,offset omatch_ANY
  885.     call    addset
  886.     jmp    makepat_2
  887. ;this really belongs at the end of makepat, but the short jump can't get there.
  888. makepat_0:
  889.     mov    ax,offset omatch_EOS
  890.     call    addset
  891.     cmp    paren_count,0        ;did we match all the parens?
  892.     jne    makepat__0_2        ;no, it's bad.
  893.     cmp    di,dx            ;did we fill up the space?
  894.     jne    makepat__0_1        ;no.
  895. makepat__0_2:
  896.     stc                ;yes, it's bad.
  897.     ret
  898. makepat__0_1:
  899.     clc
  900.     ret
  901. makepat_3:
  902.     cmp    al,'^'
  903.     jne    makepat_7
  904.     lea    ax,[si-1]        ;get the buffer pointer.
  905.     cmp    ax,inpat_ptr        ;are we at the beginning?
  906.     jne    makepat_6        ;no - this can't be it.
  907.     mov    ax,offset omatch_BOL
  908.     call    addset
  909.     jmp    makepat_2
  910. makepat_6:
  911.     mov    al,'^'
  912.     call    addchar
  913.     jmp    makepat_2
  914. makepat_7:
  915.     cmp    al,'$'
  916.     jne    makepat_8
  917.     cmp    word ptr [si],'\' + '|'*256;is the '$' at the end of an alternation?
  918.     je    makepat_7a        ;no - not special.
  919.     cmp    byte ptr [si],0        ;is the '$' at the end?
  920.     jne    makepat_9        ;no - not special.
  921. makepat_7a:
  922.     mov    ax,offset omatch_EOL
  923.     call    addset
  924.     jmp    makepat_2
  925. makepat_9:
  926.     call    addchar
  927.     jmp    makepat_2
  928. makepat_8:
  929.     cmp    al,'['
  930.     jne    makepat_10
  931.     call    getccl
  932.     jnc    makepat_2
  933.     pop    di
  934.     stc
  935.     ret
  936. makepat_10:
  937.     cmp    al,'*'
  938.     jne    makepat_11
  939.     cmp    last_pattern,0        ;is last_pattern>0?
  940.     jnge    makepat_12        ;no - not closure.
  941.     mov    bx,last_pattern
  942.     mov    ax,word ptr [bx]
  943.     cmp    ax,offset omatch_CLO    ;trying to close a closure?
  944.     je    makepat_12        ;yes - not closure.
  945.     cmp    ax,offset omatch_BOL    ;trying to close a beginning of line?
  946.     je    makepat_12        ;yes - not closure.
  947.     call    stclos
  948.     mov    this_pattern,bx        ;remember where this one was.
  949.     jmp    makepat_2
  950. makepat_11:
  951. ;put more characters here.
  952. makepat_12:
  953.     call    addchar
  954.     jmp    makepat_2
  955. makepat_2:
  956.     mov    bx,this_pattern
  957.     mov    last_pattern,bx
  958.     jmp    makepat_1
  959.  
  960.  
  961. escaped_char:
  962.     mov    cx,offset omatch_NL
  963.     cmp    al,"n"            ;newline?
  964.     je    escaped_1
  965.  
  966.     mov    cx,offset omatch_BOB
  967.     cmp    al,"`"            ;beginning of buffer?
  968.     je    escaped_1
  969.  
  970.     mov    cx,offset omatch_EOB
  971.     cmp    al,"'"            ;end of buffer?
  972.     je    escaped_1
  973.  
  974.     mov    cx,offset omatch_WOR
  975.     cmp    al,"b"            ;beginning or end of word?
  976.     je    escaped_1
  977.  
  978.     mov    cx,offset omatch_NWR
  979.     cmp    al,"B"            ;not beginning nor end of word?
  980.     je    escaped_1
  981.  
  982.     mov    cx,offset omatch_BOW
  983.     cmp    al,"<"            ;beginning of word?
  984.     je    escaped_1
  985.  
  986.     mov    cx,offset omatch_EOW
  987.     cmp    al,">"            ;end of word?
  988.     je    escaped_1
  989.  
  990.     mov    cx,offset omatch_ISW
  991.     cmp    al,"w"            ;word character?
  992.     je    escaped_1
  993.  
  994.     mov    cx,offset omatch_NOW
  995.     cmp    al,"W"            ;not word character?
  996.     je    escaped_1
  997.  
  998.     inc    paren_count        ;increase the paren count.
  999.     mov    cx,offset omatch_PAREN
  1000.     cmp    al,"("            ;start sub-regexp?
  1001.     je    escaped_1
  1002.  
  1003.     add    paren_count,-2        ;decrease the paren count.
  1004.     mov    cx,offset omatch_EOS
  1005.     cmp    al,")"            ;stop sub-regexp?
  1006.     je    escaped_1
  1007.  
  1008.     inc    paren_count        ;oops, not a paren.
  1009.     cmp    al,'|'            ;is this an "or" operator?
  1010.     jne    addchar            ;no.
  1011.  
  1012.     mov    inpat_ptr,si        ;start a new regexp here...
  1013.     call    stor            ;store a "or" operator.
  1014.     ret
  1015. escaped_1:
  1016.     mov    ax,cx
  1017.     call    addset
  1018.     ret
  1019.  
  1020. addchar:
  1021. ;al = CHR to put.
  1022.     push    ax
  1023.     mov    ax,which_chr        ;use the right omatch_chr.
  1024.     call    addset
  1025.     pop    ax
  1026.     call    addbyte
  1027.     ret
  1028.  
  1029.  
  1030. addset:            ;only command chars call addset.
  1031.     call    addbyte
  1032.     xchg    ah,al
  1033.     call    addbyte
  1034.     xchg    ah,al
  1035.     ret
  1036.  
  1037.  
  1038. addbyte:
  1039. ;al = char to put, di->dest, dx->end of dest.
  1040.     cmp    di,dx
  1041.     je    addbyte_1
  1042.     mov    [di],al
  1043.     inc    di
  1044. addbyte_1:
  1045.     ret
  1046.  
  1047.  
  1048. stclos:
  1049. ;di->last set added + 1
  1050. ;bx->last closure added
  1051.     push    di
  1052. stclos_1:
  1053.     dec    di
  1054.     mov    al,[di]
  1055.     mov    [di+2],al
  1056.     cmp    di,bx
  1057.     jne    stclos_1
  1058. stclos_2:
  1059.     mov    word ptr [bx],offset omatch_CLO
  1060.     pop    di
  1061.     add    di,2
  1062.     ret
  1063.  
  1064.  
  1065. stor:
  1066. ;di->last set added + 1
  1067.     mov    bx,last_or
  1068.     push    di
  1069. stor_1:
  1070.     dec    di
  1071.     mov    al,[di]
  1072.     mov    [di+4],al
  1073.     cmp    di,bx
  1074.     jne    stor_1
  1075. stor_2:
  1076.     pop    di            ;get the new last set.
  1077.     add    di,4
  1078.     mov    ax,offset omatch_EOS    ;store the end of string.
  1079.     stosw
  1080.     mov    word ptr [bx],offset omatch_OR
  1081.     mov    [bx+2],di        ;remember where the next starts.
  1082.     mov    last_or,di
  1083.     ret
  1084.  
  1085.  
  1086. getccl:
  1087. ;si -> source (null terminated)
  1088. ;di -> dest, dx -> end of dest
  1089. ;return cy=1 if error.
  1090.     lodsb
  1091.     cmp    al,'^'
  1092.     jne    getccl_1
  1093.     mov    ax,offset omatch_NCCL
  1094.     call    addset
  1095.     jmp    getccl_2
  1096. getccl_1:
  1097.     dec    si            ;unparse the '^'.
  1098.     mov    ax,offset omatch_CCL
  1099.     call    addset
  1100. getccl_2:
  1101.     push    bx
  1102.     mov    bx,di
  1103.     call    addbyte            ;leave room for count
  1104.     call    dodash
  1105.     mov    ax,di
  1106.     sub    ax,bx
  1107.     dec    al
  1108.     mov    [bx],al
  1109.     pop    bx
  1110.     lodsb
  1111.     cmp    al,']'            ;now make sure that we end in ']'.
  1112.     je    getccl_3        ;yup, we do.
  1113.     dec    si            ;make si -> the null.
  1114.     stc
  1115.     ret
  1116. getccl_3:
  1117.     clc
  1118.     ret
  1119.  
  1120.  
  1121. dodash:
  1122. ;si -> source pattern (null terminated)
  1123. ;di -> destination pattern
  1124. ;dx -> end of destination pattern
  1125.     push    bx
  1126.     mov    bx,si
  1127. dodash_1:
  1128.     lodsb
  1129.     or    al,al
  1130.     je    dodash_2
  1131.     cmp    al,']'
  1132.     je    dodash_2
  1133.     cmp    al,'-'
  1134.     je    dodash_4
  1135.     call    addbyte
  1136.     jmp    dodash_1
  1137. dodash_4:
  1138.     cmp    si,bx            ;'-' at beginning?
  1139.     je    dodash_5
  1140.     cmp    [si].b,0        ;or '-' at end?
  1141.     jne    dodash_6
  1142. dodash_5:
  1143.     mov    al,'-'            ;if at beginning or at end, just a '-'
  1144.     call    addbyte
  1145.     jmp    dodash_1
  1146. dodash_6:
  1147.     mov    al,[si-2]        ;in increasing alphabetic order?
  1148.     cmp    al,[si]
  1149.     ja    dodash_5        ;no - forget it.
  1150.     call    alphanumeric        ;left char alphanumeric?
  1151.     jnc    dodash_5        ;no - forget it.
  1152.     mov    al,[si]
  1153.     call    alphanumeric        ;right char alphanumeric?
  1154.     jnc    dodash_5        ;no - forget it.
  1155.     mov    al,[si-2]
  1156. dodash_7:
  1157.     inc    al            ;pre-increment -- the first one's there.
  1158.     cmp    al,[si]
  1159.     ja    dodash_9
  1160.     call    addbyte
  1161.     jmp    dodash_7
  1162. dodash_9:
  1163.     inc    si
  1164.     jmp    dodash_1
  1165. dodash_2:
  1166.     dec    si
  1167.     pop    bx
  1168.     ret
  1169.  
  1170.  
  1171. alphanumeric:
  1172. ;return cy=1 if al is alphanumeric
  1173.     cmp    al,'0'
  1174.     jb    alphanumeric_1
  1175.     cmp    al,'9'
  1176.     jbe    alphanumeric_2
  1177.     cmp    al,'A'
  1178.     jb    alphanumeric_1
  1179.     cmp    al,'Z'
  1180.     jbe    alphanumeric_2
  1181.     cmp    al,'a'
  1182.     jb    alphanumeric_1
  1183.     cmp    al,'z'
  1184.     jbe    alphanumeric_2
  1185. alphanumeric_1:
  1186.     clc
  1187.     ret
  1188. alphanumeric_2:
  1189.     stc
  1190.     ret
  1191.  
  1192.  
  1193. init_case_table:
  1194.     push    bx
  1195.     mov    init_case,offset init_case_2
  1196.     mov    bx,0
  1197. init_case_0:
  1198.     mov    case_ignore_table[bx],bl
  1199.     inc    bl
  1200.     jne    init_case_0
  1201. ;now translate 'a' to 'A'.
  1202.     mov    bx,'a'
  1203. init_case_1:
  1204.     mov    al,bl
  1205.     sub    al,20h
  1206.     mov    case_ignore_table[bx],al
  1207.     inc    bx
  1208.     cmp    bx,'z'
  1209.     jbe    init_case_1
  1210.     pop    bx
  1211. init_case_2:
  1212.     ret
  1213.  
  1214.  
  1215. code    ends
  1216.  
  1217.     end
  1218.  
  1219.